1 =============================================================================
2 DYNAMIC LINK LIBRARY : CppCLINativeDllWrapper Project Overview
3 =============================================================================
5 /////////////////////////////////////////////////////////////////////////////
8 This C++/CLI code sample demonstrates making C++/CLI wrapper classes for a
9 native C++ DLL module that allow you to call from any .NET code to the
10 classes and functions exported by the module.
12 CSCallNativeDllWrapper/VBCallNativeDllWrapper (any .NET clients)
14 CppCLINativeDllWrapper (this C++/CLI wrapper)
16 CppDynamicLinkLibrary (a native C++ DLL module)
18 In this code sample, the CSimpleObjectWrapper class wraps the native C++
19 class CSimpleObject, and the NativeMethods class wraps the global functions
20 exported by CppDynamicLinkLibrary.dll.
22 The interoperability features supported by Visual C++/CLI offer a particular
23 advantage over other .NET languages when it comes to interoperating with
24 native modules. Apart from the traditional explicit P/Invoke, C++/CLI allows
25 implicit P/Invoke, also known as C++ Interop, or It Just Work (IJW), which
26 mixes managed code and native code almost invisibly. The feature provides
27 better type safety, easier coding, greater performance, and is more forgiving
28 if the native API is modified. You can use the technology to build .NET
29 wrappers for native C++ classes and functions if their source code is
30 available, and allow any .NET clients to access the native C++ classes and
31 functions through the wrappers.
34 /////////////////////////////////////////////////////////////////////////////
36 (The relationship between the current sample and the rest samples in
37 Microsoft All-In-One Code Framework http://1code.codeplex.com)
39 CppCLINativeDllWrapper -> CppDynamicLinkLibrary
40 The C++/CLI sample module CppCLINativeDllWrapper wraps the classes and
41 functions exported by the native C++ sample module CppDynamicLinkLibrary. The
42 wrapper classes and functions can be called by any .NET code to indirectly
43 interoperate with the native C++ classes and functions.
46 /////////////////////////////////////////////////////////////////////////////
49 Step1. Create a Visual C++ / CLR / Class Library project named
50 CppCLINativeDllWrapper in Visual Studio 2008. The project wizard generates
51 a default empty C++/CLI class:
53 namespace CppCLINativeDllWrapper {
55 public ref class Class1
57 // TODO: Add your methods for this class here.
61 Step2. Reference the native C++ DLL CppDynamicLinkLibrary.
63 Option1. Link the LIB file of the DLL by entering the LIB file name in
64 Project Properties / Linker / Input / Additional Dependencies. We can
65 configure the search path of the LIB file in Project Properties / Linker /
66 General / Additional Library Directories.
68 Option2. Select References from the Project's shortcut menu. On the
69 Property Pages dialog box, expand the Common Properties node, select
70 References, and then select the Add New Reference... button. The Add
71 Reference dialog box is displayed. This dialog lists all the libraries that
72 you can reference. The Projects tab lists all the projects in the current
73 solution and any libraries they contain. If the CppDynamicLinkLibrary
74 project is in the current solution, select CppDynamicLinkLibrary and click
75 OK in the Projects tab.
77 Step3. Including the header file that declares the functions and classes of
80 #include "CppDynamicLinkLibrary.h"
82 You can configure the search path of the header file in Project Properties /
83 C/C++ / General / Additional Include Directories.
85 Step4. Design the C++/CLI wrapper class CSimpleObjectWrapper for the native
86 C++ class CSimpleObject.
88 public ref class CSimpleObjectWrapper
91 CSimpleObjectWrapper(void);
92 virtual ~CSimpleObjectWrapper(void);
95 property float FloatProperty
98 void set(float value);
102 virtual String ^ ToString(void) override;
105 static int GetStringLength(String ^ str);
108 !CSimpleObjectWrapper(void);
111 CSimpleObject *m_impl;
114 The class wraps an instance of the native C++ class CSimpleObject. The
115 instance is pointed by the private member variable m_impl. It is
116 initialized in the constructor CSimpleObjectWrapper(void);, and is freed
117 in the desctructor (virtual ~CSimpleObjectWrapper(void);) and the finalizer
118 (!CSimpleObjectWrapper(void);).
120 CSimpleObjectWrapper::CSimpleObjectWrapper(void)
122 m_impl = new CSimpleObject();
125 CSimpleObjectWrapper::~CSimpleObjectWrapper(void)
134 CSimpleObjectWrapper::!CSimpleObjectWrapper(void)
143 The public member properties and methods of CSimpleObjectWrapper wraps those
144 of the native C++ class CSimpleObject. They redirects the calls to
145 CSimpleObject through the CSimpleObject instance pointed by m_impl. Type
146 marshaling takes place between the managed and native code.
148 float CSimpleObjectWrapper::FloatProperty::get(void)
150 return m_impl->get_FloatProperty();
153 void CSimpleObjectWrapper::FloatProperty::set(float value)
155 m_impl->set_FloatProperty(value);
158 String ^ CSimpleObjectWrapper::ToString(void)
161 HRESULT hr = m_impl->ToString(szStr, ARRAYSIZE(szStr));
164 Marshal::ThrowExceptionForHR(hr);
166 // Marshal PWSTR to System::String and return it.
167 return gcnew String(szStr);
170 int CSimpleObjectWrapper::GetStringLength(System::String ^ str)
172 // Marshal System::String to PCWSTR, and call the C++ function.
173 marshal_context ^ context = gcnew marshal_context();
174 PCWSTR pszString = context->marshal_as<const wchar_t*>(str);
175 int length = CSimpleObject::GetStringLength(pszString);
180 Step5. Design the C++/CLI wrapper class NativeMethods for the functions
181 exported by the native C++ DLL module.
184 /// Function delegate of the 'PFN_COMPARE' callback function.
187 /// The delegate type has the UnmanagedFunctionPointerAttribute. Using
188 /// this attribute, you can specify the calling convention of the native
189 /// function pointer type. In the native API's header file, the callback
190 /// PFN_COMPARE is defined as __stdcall (CALLBACK), so here we specify
191 /// CallingConvention::StdCall.
193 [UnmanagedFunctionPointer(CallingConvention::StdCall)]
194 public delegate int CompareCallback(int a, int b);
198 /// This C++/CLI class wraps the functions exported by the native C++
199 /// module CppDynamicLinkLibrary.dll.
201 public ref class NativeMethods
204 static int GetStringLength1(String ^ str);
205 static int GetStringLength2(String ^ str);
206 static int Max(int a, int b, CompareCallback ^ cmpFunc);
209 All methods in NativeMethods are declared as static for the global functions
210 exported by CppDynamicLinkLibrary. They redirect calls to the native DLL.
212 int NativeMethods::GetStringLength1(String ^ str)
214 // Marshal System::String to PCWSTR, and call the C++ function.
215 marshal_context ^ context = gcnew marshal_context();
216 PCWSTR pszString = context->marshal_as<const wchar_t*>(str);
217 int length = ::GetStringLength1(pszString);
222 int NativeMethods::GetStringLength2(String ^ str)
224 // Marshal System::String to PCWSTR, and call the C++ function.
225 marshal_context ^ context = gcnew marshal_context();
226 PCWSTR pszString = context->marshal_as<const wchar_t*>(str);
227 int length = ::GetStringLength2(pszString);
232 int NativeMethods::Max(int a, int b, CompareCallback ^ cmpFunc)
234 // Convert the delegate to a function pointer.
235 IntPtr pCmpFunc = Marshal::GetFunctionPointerForDelegate(cmpFunc);
236 return ::Max(a, b, static_cast<::PFN_COMPARE>(pCmpFunc.ToPointer()));
240 /////////////////////////////////////////////////////////////////////////////
243 Using C++ Interop (Implicit PInvoke)
244 http://msdn.microsoft.com/en-us/library/2x8kf7zx.aspx
246 How to: Wrap Native Class for Use by C#
247 http://msdn.microsoft.com/en-us/library/ms235281.aspx
250 /////////////////////////////////////////////////////////////////////////////